﻿using System;
using System.Collections.Concurrent;
using System.Reflection;
using System.Threading.Tasks;

namespace Actor.Net
{
    /// <summary>
    /// Actor方法执行参数，该类型用来标识没有返回值的方法，例如返回为void、Task类型
    /// </summary>
    /// <typeparam name="TParameter">方法调用参数</typeparam>
    public class ActorParameter<TParameter> : IReturnVoidParameter, IParameter
    {
        private Delegate excuteDelegate;
        public Task StartFuncAsync(IActor actor, MethodInfo method, object parameter)
        {
            if (this.excuteDelegate == null)
                this.excuteDelegate = DelegateBuilder<TParameter>.CreateInstanceTaskMethod(actor, method);

            return ((Func<TParameter, Task>)this.excuteDelegate)((TParameter)parameter);
        }

        public void StartFunc(IActor actor, MethodInfo method, object parameter)
        {
            if (this.excuteDelegate == null)
                this.excuteDelegate = DelegateBuilder<TParameter>.CreateInstanceActionMethod(actor, method);

            ((Action<TParameter>)this.excuteDelegate)((TParameter)parameter);
        }
    }

    /// <summary>
    /// Actor方法执行参数，该类型用来标识有返回值的方法，例如返回为Task T泛型类型
    /// </summary>
    /// <typeparam name="T">方法调用参数</typeparam>
    /// <typeparam name="TReturnValue">方法放回参数</typeparam>
    public class ActorParameter<T, TReturnValue> : IReturnTaskResultParameter, IParameter
    {
        private Delegate excuteDelegate;

        private TaskReturnResult<TReturnValue> taskReturnResult = new TaskReturnResult<TReturnValue>();
        public Type GetReturnType() => typeof(TReturnValue);

        public object GetTask(object taskCompletionSource)
        {
            return taskReturnResult.GetTask(taskCompletionSource);
        }

        public object GetTaskCompletionSource()
        {
            return taskReturnResult.GetTaskCompletionSource();
        }

        public void SetException(object taskCompletionSource, Exception exception)
        {
            taskReturnResult.SetException(taskCompletionSource, exception);
        }

        public void SetTaskResult(object taskCompletionSource, object result)
        {
            taskReturnResult.SetTaskResult(taskCompletionSource, result);
        }

        public async Task<object> StartFuncAsync(IActor actor, MethodInfo method, object parameter)
        {
            if (this.excuteDelegate == null)
                this.excuteDelegate = DelegateBuilder<T, TReturnValue>.CreateInstanceTaskResultMethod(actor, method);

            var value = await((Func<T, Task<TReturnValue>>)this.excuteDelegate)((T)parameter);
            return await Task.FromResult((object)value);
        }
    }
}